package edu.drexel.jrexel2d.physics;

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.lang.Math;
import edu.drexel.jrexel2d.objects2D.*;
import edu.drexel.jrexel2d.input.CharacterActions;

public class PhysicsObject2D {
	
	private VelocityVector velocity = new VelocityVector();
	private int mass;
	private int objId = 0;
	private String name = "";
	private int worldId = 0;
	private boolean jumping = false;
	private Point2D jumpPoint;
	private boolean isPlayer = false;
	private ArrayList<Object2D> refAll2DObjects;
	private Point2D thrownGroundLocation;
	private boolean beingThrown = false;
	private boolean beingRolled = false;
	private double currStaticFrictionCoef = 0;
	private CharacterActions rollDirection = CharacterActions.NULL;
	
	public PhysicsObject2D()
	{
		AtomicInteger atmoicInteger = new AtomicInteger();
		objId = atmoicInteger.incrementAndGet();
		mass = 1;
		refAll2DObjects = new ArrayList<Object2D>();
	}
	
	public PhysicsObject2D(VelocityVector inVelVect, int inId, ArrayList<Object2D> inRefAll2DObjects){
		
		objId = inId;
		velocity = inVelVect;
		refAll2DObjects = inRefAll2DObjects;
	}
	
    public PhysicsObject2D(VelocityVector inVelVect, int inId, ArrayList<Object2D> inRefAll2DObjects, double initAcceleration){
		
		objId = inId;
		velocity = inVelVect;
		refAll2DObjects = inRefAll2DObjects;
		velocity.setYAcceleration(initAcceleration);
	}
	
    //inDelta arrives in units milliseconds.
    //we will account for this before they are used
    //in any formulas
	public void update(int inDelta){
		
			velocity.update(inDelta, getCurrentStaticFrictionCoeff());
			updatePosition(inDelta, velocity);		
	}
	
	public void updatePosition(double inDelta, VelocityVector inVelocityVector){
		
		//convert milliseconds to seconds
		double inDeltaSeconds = inDelta / 1000;
		
		float newX = edu.drexel.jrexel2d.physics.Math.CalculatePositionCoordinate(getPosition().getXF(), inDeltaSeconds, inVelocityVector.getXVelocity(), inVelocityVector.getXAcceleration());
		float newY = edu.drexel.jrexel2d.physics.Math.CalculatePositionCoordinate(getPosition().getYF(), inDeltaSeconds, inVelocityVector.getYVelocity(), inVelocityVector.getYAcceleration());
		
		if(isJumping()){
			
			if( (this.getJumpPoint().getYF() - newY) <= 0){
				stopJumping();
				getVelocity().setYVelocity(0);
				newY = this.getJumpPoint().getYF();
			}
		}
		
		else if(isThrown()){
			
			if( (this.getThrownGroundLocation().getYF() - newY <= 0)){
				setThrown(false);
				getVelocity().setYVelocity(0);
				newY = this.getThrownGroundLocation().getYF();
				
				getVelocity().setXVelocity(0);
			}	
		}
		
        else if(isRolled()){
			
        	//Since we're evaluating velocity, we have to know which way to account for
			if( (this.getVelocity().getXVelocity() <= 0 && rollDirection == CharacterActions.MOVE_RIGHT) ||
			    (this.getVelocity().getXVelocity() >= 0 && rollDirection == CharacterActions.MOVE_LEFT) ){
				
				setRolled(false);
				
				getVelocity().setXVelocity(0);
				getVelocity().setXAcceleration(0);
				
				newX = this.getPosition().getXF();
				setCurrentStaticFrictionCoeff(0);
			}	
		}
		
		getPosition().setXF(newX);
		getPosition().setYF(newY);
		
	}
	
	public void collision(int collideObjMass, double collideObjXVel, double collideObjYVel){
		
		velocity.setXVelocity(edu.drexel.jrexel2d.physics.Math.ElasticCollision1D(velocity.getXVelocity(), this.mass, collideObjXVel, collideObjMass));
		velocity.setYVelocity(edu.drexel.jrexel2d.physics.Math.ElasticCollision1D(velocity.getYVelocity(), this.mass, collideObjYVel, collideObjMass));
	
	}
	
	public void setName(String inName){
		name = inName;
	}
	
	public String getName(){
		return name;
	}
	
	public VelocityVector getVelocity(){
		return velocity;
	}
	
	public int getMass(){
		return mass;
	}
	
	public void setWorldId(int inWorldId){
		worldId = inWorldId;
	}
	
	public void setIsPlayer(boolean playerFlag){
		isPlayer = playerFlag;
	}
	
	public boolean getIsPlayer(){
		return isPlayer;
	}
	
	public void setXPosition(float xOffset){
		getPosition().setXF(getPosition().getXF() + xOffset);
	}
	
    public void setYPosition(float yOffset){
    	getPosition().setYF(getPosition().getYF() + yOffset);
	}
    
    public float getXPosition(){
    	return getPosition().getXF();
    }
    
    public float getYPosition(){
    	return getPosition().getYF();
    }
    
    public Point2D getPosition(){
    	return getObject2DByID(this.objId).getLocation();
    }
    
    public Object2D getObject2DByID(int id){
       
    	Object2D objToReturn = null;
    	
    	for(Object2D object : refAll2DObjects){
    		
    		if(object.getId() == id){
    			objToReturn = object; 
    		}
    	}
    	
    	return objToReturn;
    }
	
	public void jump(Point2D currPosition){
		
		if(!jumping){
		
		  jumping = true;
		  jumpPoint = new Point2D(currPosition.getXF(), currPosition.getYF()); 
		  velocity.setYVelocity(-170);
		}
	}
	
	public void updateJumpPoint(float xOffset, float yOffset){
		
		jumpPoint.setXF(jumpPoint.getXF() + xOffset);
		jumpPoint.setYF(jumpPoint.getYF() + yOffset);
		
	}
	
	public Point2D getJumpPoint(){
		return jumpPoint;
	}
	
	public void stopJumping(){
		jumping = false;
	}
	
	public int getObjectId(){
		return objId;
	}
	
	public boolean isJumping(){
		return jumping;
	}
	
	public int getWorldId(){
		return worldId;
	}
	
	public Point2D getThrownGroundLocation(){
		return thrownGroundLocation;
	}
	
	public void setThrownGroundLocation(Point2D inGroundLocation){
		thrownGroundLocation = inGroundLocation;
	}
	
	public boolean isThrown(){
		return beingThrown;
	}
	
	public void setThrown(boolean thrownFlag){
		beingThrown = thrownFlag;
	}
	
	public boolean isRolled(){
		return beingRolled;
	}
	
	public void setRolled(boolean rolledFlag){
		beingRolled = rolledFlag;
	}
 
	public void throwObj(CharacterActions directionToThrow, double inGravAcceleration){
		
		int yVelocity = -80;
		int xVelocity = 100;
		
		//Determine the best we can which direction (left or right)
		//to throw the object
		if(directionToThrow == CharacterActions.MOVE_RIGHT){
			xVelocity = java.lang.Math.abs(xVelocity);
		}
		else if(directionToThrow == CharacterActions.MOVE_LEFT){
			if(xVelocity > 0){
				xVelocity *= -1;
			}
		}
		
		//this may need reset so we reset it
		velocity.setYAcceleration(Math.abs(inGravAcceleration));
		
		velocity.setYVelocity(yVelocity);
		velocity.setXVelocity(xVelocity);
		
	}
	
	public void setCurrentStaticFrictionCoeff(double inCurrStaticFriction){
		currStaticFrictionCoef = inCurrStaticFriction;
	}
	
	public double getCurrentStaticFrictionCoeff(){
		return currStaticFrictionCoef;
	}
	
	public void setRollDirection(CharacterActions inAction){
		rollDirection = inAction;
	}
	
	public CharacterActions getRollDirection(){
		return rollDirection;
	}
	
    public void rollObj(CharacterActions directionToThrow){

		int xVelocity = 100;
		
		//Determine the best we can which direction (left or right)
		//to throw the object
		if(directionToThrow == CharacterActions.MOVE_RIGHT){
			xVelocity = java.lang.Math.abs(xVelocity);
		}
		else if(directionToThrow == CharacterActions.MOVE_LEFT){
			if(xVelocity > 0){
				xVelocity *= -1;
			}
		}
		
		velocity.setYVelocity(0);
		velocity.setYAcceleration(0);
		velocity.setXVelocity(xVelocity);
		
	}
}
